package encryption

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"gitee.com/rffanlab/goutils/common"
	"io"
	"math"
	"os"
)

const FILECHUNK = 8192

// 方法：MD5加密（返回32位的md5加密字符串）
/*
*  传入参数：
*  @Param:theStr Type:string
*  @Param: Type:
*  @Param: Type:
*  返回参数：
*  @Param:string Type:string
*  @Param: Type:
 */
func Md5(theStr string) string {
	h := md5.New()
	h.Write([]byte(theStr))
	cipherStr := h.Sum(nil)
	return hex.EncodeToString(cipherStr)
}

// LargeFilemd5 方法：大文档md5
/*
*  传入参数：
*  @Param:theFilePath Type:string Comment:传入文档路径
*  返回参数：
*  @Param:themd5 Type:string Comment:md5返回值
*  @Param:err Type:error Comment:错误
 */
func LargeFilemd5(theFilepath string) (themd5 string, err error) {
	file, err := os.Open(theFilepath)
	if err != nil {
		return
	}
	defer file.Close()
	info, err := file.Stat()
	if err != nil {
		return
	}
	filesize := info.Size()
	blocks := uint64(math.Ceil(float64(filesize) / float64(FILECHUNK)))
	hash := md5.New()
	for i := uint64(0); i < blocks; i++ {
		blocksize := int(math.Min(FILECHUNK, float64(filesize-int64(i*FILECHUNK))))
		buf := make([]byte, blocksize)
		file.Read(buf)
		io.WriteString(hash, string(buf))
	}
	themd5 = hex.EncodeToString(hash.Sum(nil))
	return
}

// EncryptStrWithSalt 方法：盐值加密(盐值长度为固定4个字符串)
/*
*  传入参数：
*  @Param:strToEncrypt Type:string
*  @Param: Type:
*  @Param: Type:
*  返回参数：
*  @Param: Type:string
*  @Param: Type:
 */
func EncryptStrWithSalt(strToEncrypt string) string {
	salt := common.RandStr(4)
	logStr := strToEncrypt + salt
	encryptedStr := Md5(logStr)
	return encryptedStr + salt
}

// 方法：传入的字符串与盐值加密后的字符串的对比
/*
*  传入参数：
*  @Param:strToCompare Type:string
*  @Param:encryptStr Type:string
*  @Param: Type:
*  返回参数：
*  @Param:bool Type:bool
*  @Param:error Type:error
 */
func CompareStrToSaltEncryptedStr(strToCompare, encryptedStr string) (bool, error) {
	if len(encryptedStr) != 36 {
		return false, errors.New("Not A Vaild String To Compare")
	}
	salt := string([]rune(encryptedStr)[32:36])
	newEncrypt := Md5(strToCompare + salt)
	if newEncrypt+salt == encryptedStr {
		return true, nil
	} else {
		return false, nil
	}
}

// Filemd5 方法：小文档md5
/*
*  传入参数：
*  @Param:theFilePath Type:string Comment:传入文档路径
*  返回参数：
*  @Param:themd5 Type:string Comment:md5返回值
*  @Param:err Type:error Comment:错误
 */
func Filemd5(theFilePath string) (themd5 string, err error) {
	file, err := os.Open(theFilePath)
	if err != nil {
		return
	}
	if file == nil {
		err = errors.New("文件不存在")
	}
	hash := md5.New()
	io.Copy(hash, file)
	themd5 = hex.EncodeToString(hash.Sum(nil))
	file.Close()
	return
}
